/*
    Author: Christopher Diggins
    License: MIT Licence 1.0
    Website: http://www.cdiggins.com
*/

#include <vector>

namespace cvm
{
	const int BUFF_SIZE = 255;

	struct AnyStack
	{
	public:
		AnyStack() {
			top = data - 1;
		}
		void Swap() {
			SwapNM(0, 1);
		}
		void SwapN(int n) {
			SwapNM(0, n);
		}
		void SwapNM(int n, int m) {
			assert(top - n >= data);
			assert(top - m >= data);
			Any tmp;
			Move(At(n), tmp);
			Move(At(m), At(n));
			Move(tmp, At(m));
		}
		void CopyPush(Any& a) {
			PushNoValue();
			Copy(a, Top());
		}
		void MovePush(Any& a) {
			PushNoValue();
			Move(a, Top());
		}
		void Pull(Any& a) {
			Move(Top(), a);
			*--top;			 
		}
		void MoveTopTo(AnyStack& s) {
			assert(top > data);
			s.PushNoValue();
			s.Top().MoveFrom(*top--);
		}
		Any& Top() {
			assert(top >= data);
			assert(top < data + BUFF_SIZE);
			return *top;
		}
		Any& At(int n) {
			assert(top - n >= data);
			return *(top - n);
		}
		void PushNoValue() {
			++top;
			assert(top < data + BUFF_SIZE);
			assert(top >= data);
		}
		void Dup() {
			GetN(0);
		}
		void Pop() {
			Top().DecRef();
			Top().SetUndefined();
			--top;
		}
		void GetN(int n) {
			PushNoValue();
			Copy(At(n + 1), Top());
		}
		void SetN(int n) {
			At(n + 1).DecRef();
			At(n + 1).SetUndefined();
			Move(Top(), At(n + 1));
			--top;				
		}		
		void DigN(int n) {
			for (int i=n; i > 0; --i) 
				SwapNM(i, i - 1)
		}
		void BuryN(int n) {
			for (int i=1; i < n; ++i) 
				SwapNM(i, i - 1);
		}
		template<typename T>
		void Push(T x) {
			Any a(x);
			MovePush(a);
		}
		bool IsEmpty() {
			return top < data;
		}
		int Count() {
			return top + 1 - data;
		}
		bool IsFull() {
			return top == data + BUFF_SIZE - 1;
		}
		void Clear() {
			while (!IsEmpty()) {
				Pop();
			}
		}

	private:
	
		Any* top;
		Any data[BUFF_SIZE];
	};
}